#include <iostream>
#include <cstdio>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <cstdlib>
#include <string>
using namespace std;

// void *ThreadRoutine(void *name)
// {
//     while (1)
//     {
//         if (tickets > 0)
//         {
//             usleep(rand() % 1000); // 模拟业务过程花费的时间
//             printf("%s sells ticket:%d\n", (char *)name, tickets);
//             --tickets;
//         }
//         else
//         {
//             break;
//         }
//         usleep(rand() % 1000); // 模拟处理其他业务花费的时间
//     }
//     return nullptr;
// }

// int tickets = 100;
// // 定义一个全局的互斥锁变量，并利用宏进行初始化
// pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

// void *ThreadRoutine(void *name)
// {
//     while (1)
//     {
//         // 在访问临界资源前进行加锁
//         pthread_mutex_lock(&mtx);
//         if (tickets > 0)
//         {
//             usleep(rand() % 1000); // 模拟业务过程花费的时间
//             printf("%s sells ticket:%d\n", (char *)name, tickets);
//             --tickets;
//             // 不再访问临界资源时需要解锁。
//             pthread_mutex_unlock(&mtx);
//         }
//         else
//         {
//             // 不再访问临界资源时需要解锁。
//             pthread_mutex_unlock(&mtx);
//             break;
//         }
//         // 在此处解锁？不行，如果线程执行break，就不会解锁互斥锁。其他线程会被一直阻塞。

//         usleep(rand() % 1000); // 模拟处理其他业务花费的时间
//     }
//     return nullptr;
// }

// int main()
// {
//     srand((unsigned)time(nullptr));
//     pthread_t tid1, tid2, tid3, tid4;
//     pthread_create(&tid1, nullptr, ThreadRoutine, (void *)"child thread 1");
//     pthread_create(&tid2, nullptr, ThreadRoutine, (void *)"child thread 2");
//     pthread_create(&tid3, nullptr, ThreadRoutine, (void *)"child thread 3");
//     pthread_create(&tid4, nullptr, ThreadRoutine, (void *)"child thread 4");

//     pthread_join(tid1, nullptr);
//     pthread_join(tid2, nullptr);
//     pthread_join(tid3, nullptr);
//     pthread_join(tid4, nullptr);
//     return 0;
// }

#define THREAD_NUM 5
int tickets = 100;

//声明一个ThreadData结构体，使线程入口函数的参数更多样化。
class ThreadData
{
public:
    string _tname; //线程名
    pthread_mutex_t *_pmtx; //互斥锁变量的地址

    ThreadData(const string &tname, pthread_mutex_t *pmtx)
        : _tname(tname),
          _pmtx(pmtx){};
};

void *ThreadRoutine(void *arg)
{
    ThreadData *td = (ThreadData *)arg;
    while (1)
    {
        // 在访问临界资源前进行加锁
        pthread_mutex_lock(td->_pmtx);
        if (tickets > 0)
        {
            usleep(rand() % 1000); // 模拟业务过程花费的时间
            printf("%s sells ticket:%d\n", td->_tname.c_str(), tickets);
            --tickets;
            // 不再访问临界资源时需要解锁。
            pthread_mutex_unlock(td->_pmtx);
        }
        else
        {
            // 不再访问临界资源时需要解锁。
            pthread_mutex_unlock(td->_pmtx);
            break;
        }
        // 在此处解锁？不行，如果线程执行break，就不会解锁互斥锁。其他线程会被一直阻塞。

        usleep(rand() % 1000); // 模拟处理其他业务花费的时间
    }
    return nullptr;
}

int main()
{
    // 在主线程栈区创建互斥锁变量
    pthread_mutex_t mtx;
    // 调用pthread_mutex_init初始化互斥锁
    pthread_mutex_init(&mtx, nullptr);

    srand((unsigned)time(nullptr));

    // 循环创建子线程
    pthread_t tid[THREAD_NUM];
    for (int i = 0; i < THREAD_NUM; ++i)
    {
        string tmp = "child thread ";
        tmp += to_string(i + 1);
        ThreadData *td = new ThreadData(tmp, &mtx);
        pthread_create(tid + i, nullptr, ThreadRoutine, (void*)td);
    }
    // 循环等待子线程
    for (int i = 0; i < THREAD_NUM; ++i)
    {
        pthread_join(tid[i], nullptr);
    }
    pthread_mutex_destroy(&mtx);
    return 0;
}